package com.smart.service.impl;

import com.smart.global.GlobalWord;
import com.smart.pojo.*;
import com.smart.req.ConceptualCompleteData;
import com.smart.req.ResignCompleteData;
import com.smart.resp.UserResp;
import com.smart.service.*;
import com.smart.utils.SMUtils;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ResignProcessServiceImpl implements ResignProcessService {
    @Autowired
    RepositoryService repositoryService;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    TaskService taskService;

    @Autowired
    HistoryService historyService;

    @Autowired
    IResignBillService resignBillService;

    @Autowired
    IRoleService roleService;

    @Autowired
    IUserService userService;

    @Autowired
    IDepartmentService departmentService;

    @Autowired
    IProcessService processService;

    @Autowired
    ISalaryService salaryService;
    @Autowired
    IFinanceService financeService;

    @Override
    @Transactional
    public boolean startResignProcess(ResignBill resignBill) {
        //先保存离职记录,初始状态为0审批中
        resignBill.setStatus(0);
        boolean save = resignBillService.save(resignBill);

        //流程推进变量
        Map<String, Object> map = new HashMap<>();
        //设定离职申请人
        map.put("empId", resignBill.getUserId());
        //设定财务部审批组
        List<UserResp> financeUserList = userService.queryByDeptId(GlobalWord.FINANCE_DEPARTMENT_ID);
        List<Long> financeIds = financeUserList.stream().map(User::getId).collect(Collectors.toList());
        map.put("financeEmpIds", SMUtils.listToString(financeIds));
        //设定人事部审批组
        List<UserResp> personnelUserList = userService.queryByDeptId(GlobalWord.PERSONNEL_DEPARTMENT_ID);
        List<Long> personnelIds = personnelUserList.stream().map(User::getId).collect(Collectors.toList());
        map.put("personnelEmpIds", SMUtils.listToString(personnelIds));

        //判断是否部长申请
        User productUser = userService.getById(resignBill.getUserId());
        if (productUser.getRoleId() != null) {
            //获取角色信息
            Role role = roleService.getById(productUser.getRoleId());
            if (role.getIsDepartmentRole() == 1) {
                //判断是否部长角色
                if (role.getIsLeader() == 1) {
                    map.put("isMinister", true);
                    //设定总经理
                    User manger = userService.lambdaQuery()
                            .eq(User::getRoleId, GlobalWord.MANGER_ROLE_ID)
                            .one();
                    map.put("mangerId", manger.getId());
                } else {
                    map.put("isMinister", false);
                    Department department = departmentService.lambdaQuery().eq(Department::getId, role.getDepartmentId()).one();
                    User user = userService.lambdaQuery().eq(User::getId, department.getLeader()).one();
                    map.put("ministerId", user.getId());
                }
            } else {
                //二级审批
                map.put("isMinister", true);
                //设定总经理
                User manger = userService.lambdaQuery()
                        .eq(User::getRoleId, GlobalWord.MANGER_ROLE_ID)
                        .one();
                map.put("mangerId", manger.getId());
            }
        } else {
            //二级审批
            map.put("isMinister", true);
            //设定总经理
            User manger = userService.lambdaQuery()
                    .eq(User::getRoleId, GlobalWord.MANGER_ROLE_ID)
                    .one();
            map.put("mangerId", manger.getId());
        }


        //构造流程实例关联请假单的唯一标识
        String businessKey = GlobalWord.RESIGN_KEY + "." + resignBill.getId();
        //开启请假流程
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(GlobalWord.RESIGN_KEY, businessKey, map);
        return save & !ObjectUtils.isEmpty(processInstance);
    }

    @Override
    @Transactional
    public void complete(ResignCompleteData resignCompleteData) {
        //设置流程推进信息
        Map<String, Object> map = new HashMap<>();
        map.put("msg", resignCompleteData.getSequence());

        //获取当前任务节点
        Task task = taskService.createTaskQuery().taskId(resignCompleteData.getTaskId()).singleResult();

        //判断是否要更新离职信息
        if (resignCompleteData.getResignBill() != null) {
            resignCompleteData.getResignBill().setStatus(0);
            resignBillService.updateById(resignCompleteData.getResignBill());
        }

        //获取businessKey
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .singleResult();
        String businessKey = pi.getBusinessKey();

        //获取当前流程实例关联的研发方案
        ResignBill bill = resignBillService.getById(Long.parseLong(businessKey.split("\\.")[1]));

        //设置批注人以及批注信息
        Authentication.setAuthenticatedUserId(resignCompleteData.getUserId().toString());
        taskService.addComment(task.getId(), task.getProcessInstanceId(), resignCompleteData.getComment());

        //如果是驳回流程,更新请假单信息
        if (resignCompleteData.getSequence().equals("驳回")) {
            bill.setStatus(2);
            resignBillService.updateById(bill);
        }

        //领取流程并推进
        if (task.getAssignee() == null) {
            taskService.claim(resignCompleteData.getTaskId(), resignCompleteData.getUserId().toString());
        }
        taskService.complete(resignCompleteData.getTaskId(), map);

        //判断流程是否结束
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .singleResult();

        if (processInstance == null) {
            //流程结束，处理离职成功相关信息
            bill.setStatus(1);
            resignBillService.updateById(bill);

            //计算该用户当月工资
            Salary salary = salaryService.getByUserId(bill.getUserId());
            Calendar calendar = Calendar.getInstance();
            Date date = Date.from(bill.getResignDate().atZone( ZoneId.systemDefault()).toInstant());
            calendar.setTime(date);
            int day = calendar.getActualMaximum(Calendar.DAY_OF_MONTH) - calendar.get(Calendar.DAY_OF_MONTH);
            BigDecimal leaveAmount = salary.getBaseAmount()
                    .divide(new BigDecimal(30), 2, BigDecimal.ROUND_HALF_UP)
                    .multiply(new BigDecimal(day));
            salary.setLeaveAmount(salary.getLeaveAmount().add(leaveAmount));
            salary.setStatus(1);
            salaryService.updateById(salary);

            //保存离职工资财务记录
            Finance finance = new Finance();
            finance.setType(0);
            finance.setAmount(new BigDecimal(0)
                    .add(salary.getBaseAmount())
                    .add(salary.getRdAmount())
                    .add(salary.getBonus())
                    .add(salary.getReimbursementAmount())
                    .add(salary.getSalesAmount())
                    .subtract(salary.getPenalty())
                    .subtract(salary.getLeaveAmount()));
            financeService.save(finance);
            //更新用户状态为离职
            User user = userService.lambdaQuery().eq(User::getId, bill.getUserId()).one();
            user.setStatus(1);
            userService.updateById(user);
        }
    }

    @Override
    public Map<String, Object> getResignInfo(Long userId) {
        //构建返回Map
        Map<String, Object> map = new HashMap<>();
        //查看当前用户是否正在申请离职
        List<ResignBill> resignBills = resignBillService.lambdaQuery()
                .ne(ResignBill::getStatus, 1)
                .eq(ResignBill::getUserId, userId)
                .list();
        if (resignBills.isEmpty()) {
            map.put("isResign", false);
        } else {
            map.put("isResign", true);
            String businessKey = GlobalWord.RESIGN_KEY + "." + resignBills.get(0).getId();
            Task task = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).singleResult();
            TaskInfo taskInfo = new TaskInfo();
            taskInfo.setTaskId(task.getId());
            map.put("taskForm", processService.viewTaskForm(task.getId()));
            map.put("task", taskInfo);
        }
        return map;
    }
}
